package cn.tang.tframe.springredis.id;

import cn.tang.tframe.springredis.QtProjectRedisClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by tanghc on 17/1/23.
 */
public class RedisId {
	static final Logger logger = LoggerFactory.getLogger(RedisId.class);
	private final static String STATUS_RETURN = "OK";
	private RedisId(){}
	private static class RedisIdHolder{
		private static RedisId instance = new RedisId();
	}
	public static RedisId getInstance(){
		return RedisIdHolder.instance;
	}
	/**
	 * 获取递增的数值。首次访问时缓存中无数据返回delta。获取失败后等待1ms继续获取,最多等待maxWaitMs。最多尝试次数maxTry
	 * @param key 缓存key值
	 * @param delta 递增的步长
	 * @param maxWaitMs 最多等待的时长
	 * @param maxTry 尝试次数最大值
	 */
	public long nextNum(final String key,final long delta,final long maxWaitMs,final int maxTry) {
		logger.debug("start get nextnum: key={}, delta={},maxWaitMs={},maxTry={}",key,delta,maxWaitMs,maxTry);
		Long id = null;
		int trys = 0;
		long expireAt = System.currentTimeMillis() + maxWaitMs;
		while (id == null){
			if (maxWaitMs > 0 && System.currentTimeMillis() > expireAt) {
				break;
			}
			try {
				id = QtProjectRedisClient.getSpringRedisCache().incr(key, delta);
				if(null != id){
					return id.longValue();
				}
			} catch (Exception e) {
				logger.error("get nextnum exception: key={}, delta={},maxWaitMs={},maxTry={}", key, delta, maxWaitMs, maxTry, e);
			}
			if (maxTry > 0 && trys++ > maxTry) {
				break;
			}
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
			}
		}
		logger.error("get nextnum fail: key={}, delta={},maxWaitMs={},maxTry={}", key, delta, maxWaitMs, maxTry);
		throw new RuntimeException("get next num fail");
	}

	/**
	 * 递增id生成
	 * 最多等待3秒
	 * @param key
	 * @return
	 */
	public long nextId(final String key) {
		return nextNum(key,1,3*1000,-1);
	}

}
